#coding=utf-8

require "aio/core"

class Aio::Module::SpecialStyle::CompareWithDeviceManager < Aio::Module::SpecialStyle
  include Aio::Module

  include Aio::Ui::Verbose

  # 用于传递已经分析好的现有的device
  attr_accessor :device_manager

  # 用于传递由上一次成的device_manager信息
  attr_accessor :input_benchmark

  def initialize
    super({
      :author		=> "Elin",
      :description => "此模块用于解析两次生成的device_manager值",
    })
  end

  def parse
    # 将device_manager 中的按照{device_name => useful} 形式重新编排
    # cmds_useful为深度克隆信息，对本体无影响
    device_warning = {}
    input_benchmark_device_warning = {}
    total = device_manager.devices_number
    print_good "总共 #{total} 台设备进行比较"

    device_manager.each_devices_with_index do |device_name, device_klass, i|

      device_warning[device_name] = Aio::Base::Toolkit::DeepClone.clone(device_klass.cmds_useful)
      # 进度条
      progress_bar(total, i+1, device_name)

    end

    input_benchmark.each_devices_with_index do |device_name, device_klass, i|

      input_benchmark_device_warning[device_name] = Aio::Base::Toolkit::DeepClone.clone(device_klass.cmds_useful)
      # 进度条
      progress_bar(total, i+1, device_name)

    end

    clear_line
    clear_other_info(device_warning, input_benchmark_device_warning)
    compare(device_warning, input_benchmark_device_warning)
  end

  # 只留下要比较的两个数据有共同命令的交集,其他的命令就丢弃
  # 因为即使是保留了,产生的也是大量的垃圾信息
  def clear_other_info(device_warning, input_benchmark)
    device_arr = {}
    input_arr  = {}

    # 获得命令信息
    device_warning.each_pair 	{ |k, v| device_arr[k] = v.keys }
    input_benchmark.each_pair { |k, v| input_arr[k]  = v.keys }

    # 删除 device_warning 中多余的命令信息
    device_warning.each_pair do |name, hash|
      hash.delete_if do |k, v|
        next true unless input_arr.has_key?(name)
        input_arr[name].include?(k) ? false : true
      end
    end

    # 删除 input_benchmark 中多余的命令信息
    input_benchmark.each_pair do |name, hash|
      hash.delete_if do |k, v|
        next true unless device_arr.has_key?(name)
        device_arr[name].include?(k) ? false : true
      end
    end
  end

  def compare(cm1, cm2, opts={})
    # NOTE 待加PASS
    @config_compare = Aio::Config::Warning::Compare

    cm1_arr = []
    cm2_arr = []
    Aio::Base::Toolkit::Hash.flat_cm1(cm1,
                                  Aio::Base::Toolkit::Chain.new,
                                  cm1_arr)

    Aio::Base::Toolkit::Hash.flat_cm2(cm2,
                                  Aio::Base::Toolkit::Chain.new,
                                  cm2_arr)

    cp = find_diff_2(cm1_arr, cm2_arr)

    diff = { cm1: [], cm2: []}
    # NOTE 还需要加入config_compare
    # diff = {
    #    cm1: [ [device_name, cmd, key, str], .. ],
    #    cm2: [ [device_name, cmd, key, str], .. ]
    # }
    cp[:cm1].each do |e|
      # 加入cmd
      cmd = e[1]
      diff[:cm1] << [e.first, cmd, e[-2], e.last]
    end

    cp[:cm2].each do |e|
      diff[e.first] ||= {}
      # 加入cmd
      cmd = e[1]
      diff[:cm2] << [e.first, cmd, e[-2], e.last]
    end

    #detect_pass?(diff)

    diff
  end

  # 检查是否为需要忽略的项
  def detect_pass?(diff)

    # 当没有就返回false，表示不能跳过
    diff.each_value do |elem|

      # 取key值
      elem.delete_if do |e|
        
        key = e[2]
        if @config_compare.has_key?(key.to_sym)
          @config_compare[key] == 'pass' ? true : false
        end
      end
    end
          
  end
      


  # 低效率的双循环结构
  def find_diff(cm1, cm2)
    res = {}
    cm1_dup = cm1.dup
    cm2_dup = cm2.dup

    # res 为相同的内容
    total = cm1.size
    cm1.each_with_index do |link_1, i|

      cm2.each do |link_2|

        # 如果长度不一致，就下一个
        if link_1.size != link_2.size
          next

        else
          name_1 = long_name(link_1)
          name_2 = long_name(link_2)

          if name_1 == name_2
            cm1_dup.delete link_1
            cm2_dup.delete link_2

            # 找到了相同的就跳出小循环
            break
          end

        end
      end

      # 进度条
      progress_bar(total, i+1, '')
    end

    clear_line

    # 获得不同的内容
    res[:cm1] = cm1_dup
    res[:cm2] = cm2_dup

    res
  end

  # 将一个数组转化成一长串字符作为比较方式
  def long_name(arr)
    res = ''
    arr.each { |x| res += x.to_s }
    res
  end

  # 排序后循环，效率更高
  def find_diff_2(cm1, cm2)
    cm1.concat(cm2)
    cm1.sort! { |x, y| x.string <=> y.string }

    tmp = []
    bool = false
    cm1.each_with_index do |e, i|
      # 当为真的时候，说明是重复的，就跳过
      if bool
        bool = false
        next
      end

      # 当相等的时候，将bool 设置为true，跳过
      if e.eql? cm1[i+1]
        bool = true
        next
      end

      # 如果和下一个不相等，则说明是单独的，那么就记录
      tmp << e
    end
    
    res = { cm1: [], cm2: [] }
    tmp.each do |e|
      case e.cm_type
      when :cm1
        res[:cm1] << e.line
      when :cm2
        res[:cm2] << e.line
      end
    end

    res
  end
end
